package engine.data;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import javax.microedition.lcdui.Image;

import misc.Constant;
import misc.Persistent;

public final class Terrain extends Persistent {

	public static final byte UPGRADE_NONE = 0;

	public static final byte UPGRADE_ROAD = 1;

	public static final byte UPGRADE_RAILROAD = 2;

	public static final byte UPGRADE_FORTRESS = 4;

	public static final float MULTIPLIER_1_5 = (float) 1.5;

	public byte type;

	private byte upgrade = UPGRADE_NONE;

	private byte pp;

	public Terrain(final byte terrainType) {
		super();
		this.type = terrainType;
		this.pp = TerrainType.getPP(this.type);
		if (TerrainType.getPPB(this.type) > 0
				&& Constant.RANDOM.nextInt(Constant.MAX_RATE) < TerrainType.getPPB(this.type))
			this.pp++;
	}

	public Terrain() {
		// 
	}

	public void upgrade(final byte upgradeId) {
		this.upgrade = (byte) (this.upgrade & upgradeId);
	}

	public boolean hasUpgrade(final byte upgradeId) {
		return (this.upgrade & upgradeId) == upgradeId;
	}

	public final boolean isReachable(Unit unit) {
		//System.out.println("Naval:" + UnitType.isNaval(unit));
		//System.out.println("Ter:" + UnitType.isTerrestrial(unit));
		//System.out.println("Ocean:" + TerrainType.isOcean(this));
		if ((UnitType.isNaval(unit) && !TerrainType.isOcean(this))
			|| (UnitType.isTerrestrial(unit) && TerrainType.isOcean(this))){
			return false;			
		}
		return true;
	}

	public final boolean isIrrigable() {
		return TerrainType.getIrrigationTransformation(this.type) != TerrainType.UNDEFINED;
	}

	public boolean isMinable() {
		return TerrainType.getMiningTransformation(this.type) != TerrainType.UNDEFINED;
	}

	public byte getFP(final Player player) {
		byte fp = TerrainType.getFood(this.type);
		if (player.civilization == GovernmentType.DESPOTISM || player.civilization == GovernmentType.ANARCHY) {
			if (fp > 2)
				fp--;
		}
		if ((this.upgrade & UPGRADE_RAILROAD) == UPGRADE_RAILROAD)
			fp *= MULTIPLIER_1_5;
		return fp;
	}

	public byte getPP(final Player player) {
		byte newPP;
		if (TerrainType.getPPB(type) > 0)
			newPP = this.pp;
		else
			newPP = TerrainType.getPP(this.type);
		if (player.government == GovernmentType.DESPOTISM || player.government == GovernmentType.ANARCHY) {
			if (newPP > 2)
				newPP--;
		}
		if ((this.upgrade & UPGRADE_ROAD) == UPGRADE_ROAD)
			newPP *= MULTIPLIER_1_5;
		return newPP;
	}

	public byte getTP(final Player player, final City city, final short x, final short y) {
		byte tp = TerrainType.getTP(this.type);
		if (player.government == GovernmentType.DESPOTISM || player.government == GovernmentType.ANARCHY) {
			if (tp > 2)
				tp--;
		} else if (player.government == GovernmentType.THE_REPUBLIC || player.government == GovernmentType.DEMOCRATY) {
			if (tp > 0)
				tp++;
		}
		if (city != null) {
			if (city.x == x && city.y == y)
				tp++;
			if (city.hasBuilding(Building.COLOSSUS) && !Building.isObsolete(Building.COLOSSUS, player))
				tp++;
		}
		if ((this.upgrade & UPGRADE_RAILROAD) == UPGRADE_RAILROAD)
			tp *= MULTIPLIER_1_5;
		return tp;
	}

	public short getDB() {
		return TerrainType.getDB(this.type);
	}

	public short getMPC() {
		short mpc = TerrainType.getMPC(this.type);
		final float coeff = 3;
		if ((this.upgrade & UPGRADE_RAILROAD) == UPGRADE_RAILROAD)
			mpc = 0;
		else if ((this.upgrade & UPGRADE_ROAD) != UPGRADE_ROAD)
			mpc *= coeff;
		return mpc;
	}

	public Image getImage() {
		// TODO : prendre en compte routes + chemins de fer + forteresse
		return TerrainType.getImage(this.type);
	}

	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("Terrain[type=").append(this.type).append("]");
		return sb.toString();
	}

	void irrigate() {
		byte t = TerrainType.getIrrigationTransformation(this.type);
		if (t != TerrainType.UNDEFINED)
			this.type = t;
	}

	void mine() {
		byte t = TerrainType.getMiningTransformation(this.type);
		if (t != TerrainType.UNDEFINED)
			this.type = t;
	}

	void buildBortress() {
		this.upgrade(Terrain.UPGRADE_FORTRESS);
	}

	public void persist(final DataOutputStream dout, final boolean complete) throws IOException {
		if (complete) {
			dout.writeByte(this.pp);
			dout.writeByte(this.type);
			dout.writeByte(this.upgrade);
		}
	}

	public void resurrect(final DataInputStream din, final boolean complete) throws IOException {
		if (complete) {
			this.pp = din.readByte();
			this.type = din.readByte();
			this.upgrade = din.readByte();
		}
	}

}
